package com.quectel.cms.controller.sys;

import cn.hutool.crypto.digest.BCrypt;
import com.quectel.business.common.thirdconfig.ThirdPlatformConfigBusiness;
import com.quectel.cms.constants.CmsRedisCacheConstants;
import com.quectel.cms.constants.CmsSystemConstants;
import com.quectel.cms.controller.BaseController;
import com.quectel.cms.interceptor.LoginUserSession;
import com.quectel.cms.service.sys.ApiSysLoginService;
import com.quectel.cms.util.SessionHolder;
import com.quectel.cms.vo.sys.SysUpdatePasswordVo;
import com.quectel.core.module.officialaccounts.service.OfficialAccountsBindingService;
import com.quectel.sys.module.sys.dto.SysMenuDto;
import com.quectel.sys.module.sys.dto.SysRoleDto;
import com.quectel.sys.module.sys.dto.SysUserDto;
import com.quectel.sys.module.sys.service.*;
import com.quectel.util.common.Response;
import com.quectel.util.redis.RedisUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author: CL
 * @email: louis.cao@quectel.com
 * @date: 2019-04-04 11:07:00
 */
@RestController
@RequestMapping("sys")
@Tag(name = "SysLoginController", description = "cms登陆接口")
public class SysLoginController extends BaseController {
    @DubboReference
    private SysUserService sysUserService;
    @DubboReference
    private SysRoleService sysRoleService;
    @DubboReference
    private SysGroupService sysGroupService;
    @DubboReference
    private SysTenantService sysTenantService;
    @DubboReference
    private SysLogService sysLogService;
    @DubboReference
    private OfficialAccountsBindingService officialAccountsBindingService;

    @Autowired
    private ApiSysLoginService apiSysLoginService;

    @Autowired
    private ThirdPlatformConfigBusiness thirdPlatformConfigBusiness;

    /**
     * 登录
     */
    @PostMapping("login")
    @Operation(summary = "用户登陆")
    public Response<LoginUserSession> login(@RequestBody SysUserDto recData) {

        long t1 = System.currentTimeMillis();
        String account = recData.getAccount();
        String password = recData.getPassword();
        String captchaId = recData.getCaptchaId();
        String captcha = recData.getCaptcha();
        if (StringUtils.isEmpty(account)
                ||
                StringUtils.isEmpty(password)
                ||
                StringUtils.isEmpty(captchaId)
                ||
                StringUtils.isEmpty(captcha)

        ) {
            return Response.error("请求参数不完整");
        }
        String generateCode = RedisUtils.get(CmsRedisCacheConstants.CAPTCHA_ID + captchaId);
        if (StringUtils.isBlank(generateCode)) {
            return Response.error("验证码过期");
        }
        if (!StringUtils.equalsIgnoreCase(generateCode, captcha)) {
            return Response.error("验证码错误");
        }
        SysUserDto sysUserDto = sysUserService.selectByAccount(account);

        if (sysUserDto == null) {
            return Response.error("账号不存在");
        }
        if (sysUserDto.getExpiredTime() != null && sysUserDto.getExpiredTime().getTime() < System.currentTimeMillis()) {
            return Response.error("你的账号已过期，请联系管理员");
        }
        String wrongCount = RedisUtils.get(CmsRedisCacheConstants.WRONG_COUNT + sysUserDto.getId());
        if (StringUtils.isNotBlank(wrongCount) && Long.valueOf(wrongCount) >= 5) {
            return Response.error("该账户已被冻结，请联系管理员");
        }
        if (!BCrypt.checkpw(password, sysUserDto.getPassword())) {

            long incr = RedisUtils.incr(CmsRedisCacheConstants.WRONG_COUNT + sysUserDto.getId(), 1, 1, TimeUnit.DAYS);
            if (incr >= 5) {
                return Response.error("该账户已被冻结，请联系管理员");
            }
            return Response.error("密码错误 错误" + (5 - incr) + "次后该账户将被冻结");
        }
        //删除密码标记
        RedisUtils.del(CmsRedisCacheConstants.WRONG_COUNT + sysUserDto.getId());

        Response<LoginUserSession> response = apiSysLoginService.buildSessionBySysUser(sysUserDto);

        if (!response.isSuccess()) {
            //登录不成功
            return response;
        }

        LoginUserSession session = SessionHolder.buildRedisSession(response.getData());

        apiSysLoginService.saveLoginLog(t1, session);

        return Response.<LoginUserSession>ok().wrap(session);
    }


    /**
     * 获取用户菜单列表
     *
     * @return
     */
    @GetMapping("getUserMenus")
    @Operation(summary = "获取用户菜单列表")
    public Response<Object> getMenuInfo(@RequestParam(required = false, defaultValue = "1") Byte type) {
        List<SysMenuDto> result = new ArrayList<>();

        Long userId = SessionHolder.getSysUserId();
        List<SysRoleDto> userRoleList = sysUserService.selectById(userId).getUserRoleList();

        for (SysRoleDto sysRoleDto : userRoleList) {
            List<SysMenuDto> roleMenuList = sysRoleService.selectById(sysRoleDto.getId()).getRoleMenuList();
            for (SysMenuDto sysMenuDto : roleMenuList) {
                if (sysMenuDto.isChecked()) {
                    if (CollectionUtils.isEmpty(
                            result.stream().filter(v -> Objects.equals(v.getId(), sysMenuDto.getId())).collect(Collectors.toList())
                    )) {
                        result.add(sysMenuDto);

                    }
                }
            }
        }
        List<SysMenuDto> filteredList = result.stream().filter(o -> o.getLevel() != null && o.getLevel() < 3
        &&Objects.equals(type,o.getType())).collect(Collectors.toList());
        return Response.ok().wrap(filteredList);
    }

    private List<SysMenuDto> recursive(SysMenuDto o) {
        if (o.getSubMenus() == null || o.getSubMenus().size() <= 0) {
            return null;
        }
        List<SysMenuDto> tmp = Arrays.asList(o);
        List<SysMenuDto> sysMenuDtos = new ArrayList<>(tmp);
        for (SysMenuDto subMenu : o.getSubMenus()) {
            List<SysMenuDto> recursive = recursive(subMenu);
            if (recursive != null && recursive.size() > 0) {
                sysMenuDtos.addAll(recursive);
            }
        }
        return sysMenuDtos;
    }

    private List<SysMenuDto> treeBuild(List<SysMenuDto> list) {
        List<SysMenuDto> menus = new ArrayList<>();
        for (SysMenuDto sysMenuDto : list) {
            if (sysMenuDto.getLevel() == 0 && sysMenuDto.getType() == 1) {
                menus.add(sysMenuDto);
            }
            for (SysMenuDto menu : list) {
                if (menu.getParentId().equals(sysMenuDto.getId())) {
                    if (sysMenuDto.getSubMenus() == null) {
                        sysMenuDto.setSubMenus(new ArrayList<>());
                    }
                    sysMenuDto.getSubMenus().add(menu);
                }
            }
        }
        return menus;
    }


    /**
     * 用户更新密码
     */
    @PostMapping("updatePassword")
    @Operation(summary = "用户更新密码")
    public Response<Object> updatePassword(@RequestBody SysUpdatePasswordVo sysUpdatePasswordVo) {


        LoginUserSession loginUser = SessionHolder.getSysUser();
        if (loginUser == null) {
            return Response.error("请登录");
        }
        SysUserDto sysUserDto = sysUserService.selectByAccount(loginUser.getAccount());
        if (sysUserDto == null || !BCrypt.checkpw(sysUpdatePasswordVo.getOriginPassword(), sysUserDto.getPassword())) {
            return Response.error("原始密码错误");
        }
        if (sysUpdatePasswordVo.getPassword().length() < CmsSystemConstants.PASSWORD_MIN_LENGTH) {
            return Response.error("密码最低的长度为" + CmsSystemConstants.PASSWORD_MIN_LENGTH + "位");
        }


        sysUserService.updatePassword(loginUser.getUserId(), BCrypt.hashpw(sysUpdatePasswordVo.getPassword(), BCrypt.gensalt()));
        return Response.ok();
    }

    /**
     * 用户登出
     */
    @PostMapping("logout")
    @Operation(summary = "用户登出")
    public Response<Object> logout() {
        SessionHolder.logout();
        return Response.ok();

    }
}
